grow snapshot area from widget's allocation to cover extra widget windows
author21:04:28 Tim Janik <timj@imendio.com>
Wed, 21 May 2008 19:07:40 +0000 (19:07 +0000)
committerTim Janik <timj@src.gnome.org>
Wed, 21 May 2008 19:07:40 +0000 (19:07 +0000)
2008-05-21 21:04:28  Tim Janik  <timj@imendio.com>

        * gtk/gtkwidget.c gtk_widget_get_snapshot(): grow snapshot area from
        widget's allocation to cover extra widget windows placed outside the
        widget allocation (spinbutton arrows are the prime example for this).

svn path=/trunk/; revision=20123

ChangeLog
gtk/gtkwidget.c

index bd181cfce339c9c1e565c32cf0887a54d5ad1614..f0c2eb3d81f7f4705d27821c14089fa7f27191cf 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2008-05-21 21:04:28  Tim Janik  <timj@imendio.com>
+
+       * gtk/gtkwidget.c gtk_widget_get_snapshot(): grow snapshot area from
+       widget's allocation to cover extra widget windows placed outside the
+       widget allocation (spinbutton arrows are the prime example for this).
+
 2008-03-18 10:49:20  Tim Janik  <timj@imendio.com>
 
        * Applied pixmap redirection patch by Alexander Larsson with
index 1f4f9fbd09bd52c4730300ea60b9ab584dc0c6c6..287c6e6d2204aa845fbf5c6abb68651b7e154a18 100644 (file)
@@ -8328,34 +8328,82 @@ gtk_widget_unref (GtkWidget *widget)
 GdkPixmap*
 gtk_widget_get_snapshot (GtkWidget *widget)
 {
+  int x, y, width, height;
+  GdkWindow *parent_window = NULL;
   GdkPixmap *pixmap;
-  int x, y;
 
+  if (widget->parent && !GTK_WIDGET_REALIZED (widget->parent))
+    gtk_widget_realize (widget->parent);
   if (!GTK_WIDGET_REALIZED (widget))
     gtk_widget_realize (widget);
 
-  pixmap = gdk_pixmap_new (widget->window,
-                          widget->allocation.width,
-                          widget->allocation.height,
-                          gdk_drawable_get_depth (widget->window));
-  if (GTK_WIDGET_NO_WINDOW (widget))
+  /* figure snapshot rectangle */
+  x = widget->allocation.x;
+  y = widget->allocation.y;
+  width = widget->allocation.width;
+  height = widget->allocation.height;
+  GList *windows = NULL, *list;
+  if (widget->parent && !GTK_WIDGET_NO_WINDOW (widget))
     {
-      x = widget->allocation.x;
-      y = widget->allocation.y;
+      parent_window = gtk_widget_get_parent_window (widget);
+      for (list = gdk_window_peek_children (parent_window); list; list = list->next)
+        {
+          GdkWindow *subwin = list->data;
+          gpointer windata;
+          int wx, wy, ww, wh;
+          gdk_window_get_user_data (subwin, &windata);
+          if (windata != widget)
+            continue;
+          windows = g_list_prepend (windows, subwin);
+          gdk_window_get_position (subwin, &wx, &wy);
+          gdk_drawable_get_size (subwin, &ww, &wh);
+          /* grow snapshot rectangle by extra widget sub window */
+          if (wx < x)
+            {
+              width += x - wx;
+              x = wx;
+            }
+          if (wy < y)
+            {
+              height += y - wy;
+              y = wy;
+            }
+          if (x + width < wx + ww)
+            width += wx + ww - (x + width);
+          if (y + height < wy + wh)
+            height += wy + wh - (y + height);
+        }
+    }
+  else if (!widget->parent)
+    x = y = 0; /* toplevel */
+
+  /* render snapshot */
+  pixmap = gdk_pixmap_new (widget->window, width, height, gdk_drawable_get_depth (widget->window));
+  for (list = windows; list; list = list->next)
+    {
+      GdkWindow *subwin = list->data;
+      int wx, wy;
+      gdk_window_get_position (subwin, &wx, &wy);
+      gdk_window_redirect_to_drawable (subwin, pixmap, MAX (0, x - wx), MAX (0, y - wy),
+                                       wx - x, wy - y, width, height);
+      gdk_window_invalidate_rect (subwin, NULL, TRUE);
+    }
+  if (!windows) /* NO_WINDOW || toplevel */
+    {
+      gdk_window_redirect_to_drawable (widget->window, pixmap, x, y, 0, 0, width, height);
+      gdk_window_invalidate_rect (widget->window, NULL, TRUE);
     }
-  else
-    x = y = 0;
-
-  gdk_window_redirect_to_drawable (widget->window,
-                                  pixmap,
-                                  x, y,
-                                  0, 0,
-                                  widget->allocation.width,
-                                  widget->allocation.height);
   gtk_widget_queue_draw (widget);
+  if (parent_window)
+    gdk_window_process_updates (parent_window, TRUE);
+  for (list = windows; list; list = list->next)
+    gdk_window_process_updates (list->data, TRUE);
   gdk_window_process_updates (widget->window, TRUE);
-  gdk_window_remove_redirection (widget->window);
-
+  for (list = windows; list; list = list->next)
+    gdk_window_remove_redirection (list->data);
+  if (!windows) /* NO_WINDOW || toplevel */
+    gdk_window_remove_redirection (widget->window);
+  g_list_free (windows);
   return pixmap;
 }